package com.wang.jmonkey.modules.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.jmonkey.common.exception.ServiceException;
import com.wang.jmonkey.common.utils.TreeUtil;
import com.wang.jmonkey.modules.system.mapper.SystemDeptMapper;
import com.wang.jmonkey.modules.system.model.dto.SystemDeptTreeDto;
import com.wang.jmonkey.modules.system.model.entity.SystemDeptEntity;
import com.wang.jmonkey.modules.system.model.enums.SystemAclPrincipalTypeEnum;
import com.wang.jmonkey.modules.system.model.enums.SystemDaclPrincipalTypeEnum;
import com.wang.jmonkey.modules.system.service.SystemAclService;
import com.wang.jmonkey.modules.system.service.SystemDaclService;
import com.wang.jmonkey.modules.system.service.SystemDeptService;
import com.wang.jmonkey.redis.utils.LockUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;

/**
 * 机构部门信息(SystemDept)表服务实现类
 *
 * @author HeJiawang
 * @since 2021-05-14 16:12:04
 */
@Service
public class SystemDeptServiceImpl extends ServiceImpl<SystemDeptMapper, SystemDeptEntity> implements SystemDeptService {

    @Autowired
    private SystemDeptMapper mapper;

    @Autowired
    private SystemAclService systemAclService;

    @Autowired
    private SystemDaclService systemDaclService;

    /**
     * 事务锁key <br/>
     * 在新增或修改信息时，要维护path字段，所以要锁资源
     */
    private static final String LOCK_KEY = "SYSTEM_DEPT_LOCK_KEY";


    /**
     * 维护path字段信息
     * @param entity 机构部门信息
     */
    private void buildDeptPath (SystemDeptEntity entity) {
        String path = StrUtil.EMPTY;

        if (ObjectUtil.isNotEmpty(entity.getParentId())) {
            SystemDeptEntity parentDept = mapper.selectById(entity.getParentId());
            if (ObjectUtil.isEmpty(parentDept)) throw new ServiceException("上级机构部门信息已不存在");

            // 维护path字段
            path = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(parentDept.getPath()) ? StrUtil.EMPTY : parentDept.getPath(),
                    parentDept.getId()
            );
        }

        entity.setPath(path);
    }

    /**
     * 新增机构部门
     * @param entity 机构部门信息
     * @return true 新增成功
     */
    @Override
    public boolean save(SystemDeptEntity entity) {
        try {
            LockUtil.lock(LOCK_KEY);

            // 维护path字段值
            buildDeptPath(entity);

            return super.save(entity);
        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 修改机构部门
     * @param entity 机构部门信息
     * @return true 修改成功
     */
    @Transactional
    @Override
    public boolean updateById(SystemDeptEntity entity) {
        try {
            LockUtil.lock(LOCK_KEY);


            SystemDeptEntity dept = mapper.selectById(entity.getId());
            if (ObjectUtil.isEmpty(dept)) throw new ServiceException("机构部门信息不存在");

            // 维护path字段值
            buildDeptPath(entity);

            // 更新下级区域信息path字段值
            String oldPath = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(dept.getPath()) ? StrUtil.EMPTY : dept.getPath(),
                    dept.getId()
            );
            String newPath = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(entity.getPath()) ? StrUtil.EMPTY : entity.getPath(),
                    entity.getId()
            );

            return super.updateById(entity) && mapper.refreshPath(oldPath, newPath) >= 0;
        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 删除机构部门
     * @param id 机构部门id
     * @return true 删除成功
     */
    @Transactional
    @Override
    public boolean removeById(Serializable id) {
        try {
            LockUtil.lock(LOCK_KEY);

            SystemDeptEntity dept = mapper.selectById(id);
            if (ObjectUtil.isEmpty(dept)) return false;

            // 根据path删除下级区域
            String path = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(dept.getPath()) ? StrUtil.EMPTY : dept.getPath(),
                    dept.getId()
            );
            QueryWrapper<SystemDeptEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("path", path);

            // 有时间优化数据库操作频次
            List<SystemDeptEntity> deptList = super.list(queryWrapper);
            if (CollUtil.isNotEmpty(deptList)) {
                deptList.forEach(deptEntity -> {
                    systemAclService.deleteByPrincipalId(deptEntity.getId(), SystemAclPrincipalTypeEnum.DEPT);
                    systemDaclService.deleteByPrincipalId(deptEntity.getId(), SystemDaclPrincipalTypeEnum.DEPT);
                });

                super.remove(queryWrapper);
            }

            return super.removeById(id)
                    &&systemAclService.deleteByPrincipalId(id, SystemAclPrincipalTypeEnum.DEPT)
                    &&systemDaclService.deleteByPrincipalId(id, SystemDaclPrincipalTypeEnum.DEPT);

        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 获取树形结构数据
     * @return 树形结构数据集合
     */
    @Override
    public List<SystemDeptTreeDto> listTree() {
        List<SystemDeptTreeDto> treeDtoList = mapper.listTree();
        return TreeUtil.build(treeDtoList);
    }
}
